/*
 * @Description:
 * @Author: fhw
 * @Date: 2023-02-17 15:49:02
 */
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Reflector } from '@nestjs/core'; // 反射器，作用与自定义装璜器桥接
import { throwHttp } from 'src/utlis';
import { isTrue } from 'src/utlis/tools';
import { TokenDto } from './constants';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly jwtService: JwtService,
  ) { }

  // 白名单数组
  private whiteUrlList: string[] = ['/admin-user/login'];

  // 验证该次申请是否为白名单内的路由
  private isWhiteUrl(urlList: string[], url: string): boolean {
    if (urlList.includes(url)) {
      return true;
    }
    return false;
  }

  canActivate(context: ExecutionContext): boolean {
    // 获取申请对象
    const request = context.switchToHttp().getRequest();
    // 验证是否是白名单内的路由
    if (this.isWhiteUrl(this.whiteUrlList, request.url)) return true;

    /** 是否放行 */
    const isPublic = this.reflector.getAllAndOverride('isPublic', [
      context.getHandler(),
      context.getClass(),
    ]);

    if (isPublic) return true;

    // 获取申请头中的token字段，解析获取存储在token的用户信息
    const token = context
      .switchToRpc()
      .getData()
      .headers.authorization?.split(' ') as string[];
    const user: TokenDto = this.jwtService.decode(isTrue(token) ? token[1] : '') as TokenDto;

    if (!user) throwHttp('token获取失败，请传递token或书写正确');

    // 应用反射器，配合装璜器应用，获取装璜器传递过去的数据
    /** 角色验证 */
    const authRoles = this.reflector.get<string[]>(
      'roles',
      context.getHandler(),
    );
    // 如果没有应用roles装璜，就获取不到值，就不鉴权，等于白名单
    if (!isTrue(authRoles)) return true;

    // 如果用户的所属角色与装璜器传递过去的值匹配则通过，否则不通过
    const userRoles = user.roles;
    return authRoles.includes(userRoles?.rolename)
  }
}
